package com.btb.adapter.service;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

import com.alibaba.fastjson.JSON;
import com.btb.adapter.constant.Constants;
import com.btb.adapter.contract.ActFishService;
import com.btb.adapter.contract.ActHeroService;
import com.btb.adapter.mapper.UpChainFishMapper;
import com.btb.adapter.mapper.UpChainFishPartMapper;
import com.btb.adapter.mapper.UpChainHeroMapper;
import com.btb.adapter.model.TransferRecord;
import com.btb.adapter.model.UpChainFish;
import com.btb.adapter.model.UpChainFishExample;
import com.btb.adapter.model.UpChainFishPart;
import com.btb.adapter.model.UpChainFishPartExample;
import com.btb.adapter.model.UpChainHero;
import com.btb.adapter.model.UpChainHeroExample;
import com.btb.adapter.utils.Fmt;
import com.btb.adapter.utils.Web3jUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;

import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UpChainBlockService {
	@Autowired
	private Credentials credentials;
	@Autowired
	private UpChainHeroMapper upChainHeroMapper;
	@Autowired
	private UpChainFishMapper upChainFishMapper;
	@Autowired
	private UpChainFishPartMapper upChainFishPartMapper;
	@Autowired
	private  ActHeroService actHeroService;

	@Autowired
	private ActFishService actFishService;


	public List<UpChainHero> queryHero() {
		Page<UpChainHero> page = PageHelper.startPage(1, Constants.UP_CHAIN_PAGE_SIZE).doSelectPage(() -> {
			UpChainHeroExample example = new UpChainHeroExample();
			example.createCriteria().andStatusEqualTo(Constants.UP_CHAIN_STATU_ZERO); // 只查未上链的
			upChainHeroMapper.selectByExample(example);
		});
		return page.getResult();
	}
	public void upChain(final UpChainHero hero) {
		// 先更新为上链中
		final UpChainHero updateRecord = UpChainHero.builder().id(hero.getId()).status(Constants.UP_CHAIN_STATUS_ONE).build();
		upChainHeroMapper.updateByPrimaryKeySelective(updateRecord);
		String address = hero.getOwner();
		Integer clientId = hero.getClientId();
		Integer heroArea = hero.getHeroArea();
		Integer grade = hero.getGrade();
		String season = hero.getSeason();
		Long powerValue = hero.getPowerValue();
		Long productionDate = hero.getProductionDate();
		TransactionReceipt upChain = null;
		String errMsg = "";
		try {
			upChain = actHeroService.upChain(address,
					Fmt.intToBig(clientId),
					Fmt.intToBig(heroArea),
					Fmt.intToBig(grade),
					new BigInteger(season),
					Fmt.logToBig(powerValue),
					Fmt.logToBig(productionDate),
					hero.getName(), hero.getCardTips(), hero.getCardImage());
		} catch (Exception e) {
			errMsg = e.getMessage();
			log.error("upChain up_chain_hero id:{},err:{}",hero.getId(),e.getMessage(),e);
		}
		if(Objects.nonNull(upChain)) {
			UpChainHero record = UpChainHero.builder()
					.id(hero.getId())
					.status(Constants.UP_CHAIN_STATUS_ONE) // 更新为上链中状态
					.startUpChainTimestamp(new Date().getTime())
					.transactionHash(upChain.getTransactionHash())
					.address(credentials.getAddress())
					.gasUsed(new BigDecimal(Web3jUtils.fmt(upChain.getGasUsed())))
					.build();
			upChainHeroMapper.updateByPrimaryKeySelective(record);
		}else {
			UpChainHero record = UpChainHero.builder()
					.id(hero.getId())
					.status(Constants.UP_CHAIN_STATUS_FOUE) // 更新为上链失败状态
					.startUpChainTimestamp(new Date().getTime())
					.errDesc(errMsg)
					.build();
			upChainHeroMapper.updateByPrimaryKeySelective(record);
		}
	}
	@Transactional(rollbackFor = Exception.class)
	public void upChainHero() {
		List<UpChainHero> query = queryHero();
		query.forEach(x->{
			upChain(x);
		});
	}
	public List<UpChainFish> queryFish() {
		Page<UpChainFish> page = PageHelper.startPage(1, Constants.UP_CHAIN_PAGE_SIZE).doSelectPage(() -> {
			UpChainFishExample example = new UpChainFishExample();
			example.createCriteria().andStatusEqualTo(Constants.UP_CHAIN_STATU_ZERO); // 只查未上链的
			upChainFishMapper.selectByExample(example);
		});
		return page.getResult();
	}
	@Transactional(rollbackFor = Exception.class)
	public void upChainFish() {
		List<UpChainFish> query = queryFish();
		query.forEach(x->{
			upChain(x);
		});
	}

	public void upChain(final UpChainFish fish) {
		final UpChainFish updateRecord = UpChainFish.builder().id(fish.getId()).status(Constants.UP_CHAIN_STATUS_ONE).build();
		upChainFishMapper.updateByPrimaryKeySelective(updateRecord);
		String address = fish.getOwner();
		Integer clientId = fish.getClientId();
		String season = fish.getSeason();
		Integer race = fish.getRace();
		Long productionDate = fish.getProductionDate();
		Integer type = fish.getType();
		Long transactionNum = Optional.ofNullable(fish.getTransactionNum()).orElse(0L);
		String cardTips = fish.getCardTips();
		String cardImage = fish.getCardImage();
		List<UpChainFishPart> queryFishPart = queryFishPart(clientId);
		String parts = JSON.toJSONString(queryFishPart);
		String errMsg = StringUtils.EMPTY;
		TransactionReceipt upChain = null;
		try {
			upChain = actFishService.upChain(address, Fmt.intToBig(clientId), new BigInteger(season),
					Fmt.intToBig(race),Fmt.logToBig(productionDate), Fmt.intToBig(type),
					Fmt.intToBig(transactionNum.intValue()), cardTips, cardImage, parts);
		} catch (Exception e) {
			log.error("upChainFish err:{}", e.getMessage(), e);
		}
		if(Objects.nonNull(upChain)) {
			UpChainFish record = UpChainFish.builder()
					.id(fish.getId())
					.status(Constants.UP_CHAIN_STATUS_ONE) // 上链中
					.startUpChainTimestamp(new Date().getTime())
					.transactionHash(upChain.getTransactionHash())
					.address(credentials.getAddress())
					.gasUsed(new BigDecimal(Web3jUtils.fmt(upChain.getGasUsed())))
					.build();
			upChainFishMapper.updateByPrimaryKeySelective(record);
		}else {
			UpChainFish record = UpChainFish.builder()
					.id(fish.getId())
					.status(Constants.UP_CHAIN_STATUS_FOUE) // 失败
					.startUpChainTimestamp(new Date().getTime())
					.errDesc(errMsg)
					.build();
			upChainFishMapper.updateByPrimaryKeySelective(record);
		}

	}
	private List<UpChainFishPart> queryFishPart(final Integer clientId){
		UpChainFishPartExample example = new UpChainFishPartExample();
		example.createCriteria().andUpChainFishClientIdEqualTo(clientId);
		return upChainFishPartMapper.selectByExample(example);
	}
}

